;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2018, 2019 Kei Kebreau <kkebreau@posteo.net>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (wii-homebrew)
  #:use-module (guix packages)
  #:use-module (gnu packages)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (guix download)
  #:use-module (guix git-download)
  #:use-module (guix gexp)
  #:use-module (guix utils)
  #:use-module (guix build-system gnu)
  #:use-module (guix build-system trivial)
  #:use-module (gnu build cross-toolchain)
  #:use-module (gnu packages autotools)
  #:use-module (gnu packages base)
  #:use-module (gnu packages compression)
  #:use-module (gnu packages cross-base)
  #:use-module (gnu packages fontutils)
  #:use-module (gnu packages gcc)
  #:use-module (gnu packages gl)
  #:use-module (gnu packages image)
  #:use-module (gnu packages multiprecision)
  #:use-module (gnu packages ncurses)
  #:use-module (gnu packages pkg-config)
  #:use-module (gnu packages texinfo)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-26)
  #:use-module (ice-9 match))

(define %patch-dir
  (string-append (if (current-filename)
                     (dirname (current-filename))
                     ".")
                 "/patches"))

;; For GCC, from gnu/packages/cross-base.scm.
(define %gcc-include-paths
  ;; Environment variables for header search paths.
  ;; Note: See <http://bugs.gnu.org/22186> for why not 'CPATH'.
  '("C_INCLUDE_PATH"
    "CPLUS_INCLUDE_PATH"
    "OBJC_INCLUDE_PATH"
    "OBJCPLUS_INCLUDE_PATH"))
(define %gcc-cross-include-paths
  ;; Search path for target headers when cross-compiling.
  (map (cut string-append "CROSS_" <>) %gcc-include-paths))

(define wii-target "powerpc-eabi")
(define wii-newlib-version "3.1.0")
(define wii-newlib-source
  (origin
    (method url-fetch)
    (uri (string-append "ftp://sourceware.org/pub/newlib/newlib-"
                        wii-newlib-version ".tar.gz"))
    (sha256
     (base32
      "0ahh3n079zjp7d9wynggwrnrs27440aac04340chf1p9476a2kzv"))
    (patches
     (list
      (local-file
       (string-append %patch-dir
                      "/wii-newlib.patch"))))))

(define devkit-buildscripts-source
  (let ((version "devkitPPC_r35"))
    (origin
      (method git-fetch)
      (uri (git-reference
            (url "https://github.com/devkitPro/buildscripts.git")
            (commit version)))
      (file-name (git-file-name "devkit-buildscripts" version))
      (sha256
       (base32
        "02ir1wdc647g3vik7sfhyshsz6irj8n6na5jw79m628sx9f0nya7")))))

(define devkitppc-rules-source
  (let ((commit "0a1d9c0341a6800f9c7084a50ee93d6e2bb97fa2"))
    (origin
      (method git-fetch)
      (uri (git-reference
            (url "https://github.com/devkitPro/devkitppc-rules.git")
            (commit commit)))
      (file-name (git-file-name "devkitppc-rules" commit))
      (sha256
       (base32
        "107hlg2l6mb4c87p9906v36km15mh7arycqizblfgbmq3x36pj51")))))

(define-public wii-binutils
  (let ((xbinutils (cross-binutils wii-target)))
    (package
      (inherit xbinutils)
      (name "wii-binutils")
      (version "2.32")
      (source
       (origin
         (inherit (package-source xbinutils))
         (method url-fetch)
         (uri (string-append "mirror://gnu/binutils/binutils-"
                             version ".tar.lz"))
         (sha256
          (base32
           "0hcjbhfa7g4cdi3ljfyml3jjg90aqz4fpam669gp36l5h1fbcdhi"))
         (patches
          (append
           (origin-patches (package-source xbinutils))
           (list
            (local-file
             (string-append %patch-dir "/wii-binutils.patch")))))))
      (arguments
       `(,@(substitute-keyword-arguments (package-arguments xbinutils)
            ((#:configure-flags flags)
             `(cons* "--disable-werror"
                     "--enable-plugins"
                     "--with-system-zlib"
                     "--disable-nls"
                     "--enable-lto"
                     ,flags)))))
      (inputs
       `(("zlib" ,zlib))))))

(define-public mn10200-binutils
  (let ((xbinutils (cross-binutils "mn10200")))
    (package
      (inherit xbinutils)
      (name "mn10200-binutils")
      (version "2.17")
      (source
       (origin
         (inherit (package-source xbinutils))
         (method url-fetch)
         (uri (string-append "mirror://gnu/binutils/binutils-"
                             version ".tar.bz2"))
         (sha256
          (base32
           "0jd5nvi8nmkdlp4q6dpm6jxxs0y230xgd9nh141sz6m944qkddmq"))
         (patches '())))
      (arguments
       `(#:make-flags '("CFLAGS=-std=c99")
         #:modules ((guix build gnu-build-system)
                    (guix build utils)
                    (srfi srfi-1))
         #:phases
         (modify-phases %standard-phases
           (replace 'configure
             ;; configure does not work followed by "SHELL=..." and
             ;; "CONFIG_SHELL=..."; set environment variables instead
             (lambda* (#:key configure-flags #:allow-other-keys)
               (setenv "SHELL" (which "bash"))
               (setenv "CONFIG_SHELL" (which "bash"))
               (setenv "LDFLAGS" "-static-libgcc")
               (apply invoke (cons "./configure"
                                   (remove (lambda (flag)
                                             (string-prefix? "LDFLAGS" flag))
                                           configure-flags))))))
         ,@(substitute-keyword-arguments (package-arguments xbinutils)
            ((#:configure-flags flags)
             `(cons* "--disable-werror"
                     "--enable-plugins"
                     "--with-system-zlib"
                     "--disable-nls"
                     "--disable-multilib"
                     "--enable-lto"
                     ;; This was $CROSS_PARAMS
                     (string-append "--build=" ,(nix-system->gnu-triplet))
                     (string-append "--prefix=" (assoc-ref %outputs "out"))
                     ,flags)))))
      (inputs
       `(("zlib" ,zlib))))))

(define-public wii-bootstrap-gcc
  (package
    (name "wii-bootstrap-gcc")
    (version "8.3.0")
    (source
     (origin
       (method url-fetch)
       (uri (string-append "mirror://gnu/gcc/gcc-" version
                           "/gcc-" version ".tar.xz"))
       (sha256
        (base32
         "0b3xv411xhlnjmin2979nxcbnidgvzqdf4nbhix99x60dkzavfk4"))
       (patches
        (list
         (local-file
          (string-append %patch-dir
                         "/gcc-8-cross-environment-variables.patch"))
         (local-file
          (string-append %patch-dir
                         "/wii-gcc.patch"))))))
    (build-system gnu-build-system)
    (native-inputs
     `(("ld-wrapper-cross" ,(make-ld-wrapper
                             (string-append "ld-wrapper-" wii-target)
                             #:target (const wii-target)
                             #:binutils wii-binutils))
       ("wii-binutils" ,wii-binutils)))
    (inputs
     `(("gmp" ,gmp)
       ("mpfr" ,mpfr)
       ("mpc" ,mpc)
       ("zlib" ,zlib)))
    (arguments
     `(#:strip-binaries? #f
       #:out-of-source? #t
       #:tests? #f
       #:configure-flags
       (list
        (string-append "--prefix=" %output)
        ;; Disable features not needed at this stage.
        "--disable-decimal-float" ;would need libc
        "--disable-libatomic"
        "--disable-libgomp"
        "--disable-libitm"
        "--disable-libmpx"
        "--disable-libmudflap"
        "--disable-libquadmath"
        "--disable-libsanitizer"
        "--disable-libssp"
        "--disable-libstdcxx"
        "--disable-libstdcxx-pch"
        "--disable-libstdcxx-verbose"
        "--disable-libvtv"
        "--disable-multilib"
        "--disable-nls"
        "--disable-shared"
        "--disable-threads" ;libgcc, would need libc
        "--disable-tls"
        "--disable-werror"
        "--enable-languages=c,c++"
        "--with-system-zlib"

        (string-append "--target=" ,wii-target)
        "--with-newlib"
        "--without-headers"
        "--with-cpu=750")
       #:phases
       (modify-phases %standard-phases
         (replace 'build
           (lambda _
             (invoke "make" "-j" (number->string (parallel-job-count))
                     "all-gcc")))
         (replace 'install
           (lambda _
             (invoke "make" "-j" (number->string (parallel-job-count))
                     "install-gcc")))
         ;; From Guix's gnu/build/cross-toolchain.scm.
         (add-after 'install 'make-cross-binutils-visible
           (lambda* (#:key inputs outputs #:allow-other-keys)
             (let* ((out      (assoc-ref outputs "out"))
                    (libexec  (string-append out "/libexec/gcc/" ,wii-target))
                    (binutils (string-append (assoc-ref inputs "wii-binutils")
                                             "/bin/" ,wii-target "-"))
                    (wrapper  (string-append (assoc-ref inputs "ld-wrapper-cross")
                                             "/bin/" ,wii-target "-ld")))
               (for-each (lambda (file)
                           (symlink (string-append binutils file)
                                    (string-append libexec "/" file)))
                         '("as" "nm"))
               (symlink wrapper (string-append libexec "/ld"))
               #t))))))
    ;; Only search target inputs, not host inputs.
    (search-paths (cons (search-path-specification
                         (variable "CROSS_LIBRARY_PATH")
                         (files '("lib" "lib64")))
                        (map (lambda (variable)
                               (search-path-specification
                                (variable variable)
                                (files '("include"))))
                             %gcc-cross-include-paths)))
    (native-search-paths
     (list (search-path-specification
            (variable "CROSS_C_INCLUDE_PATH")
            (files (list (string-append wii-target "/include"))))
           (search-path-specification
            (variable "CROSS_CPLUS_INCLUDE_PATH")
            (files (list (string-append wii-target "/include"))))
           (search-path-specification
            (variable "CROSS_LIBRARY_PATH")
            (files (list (string-append wii-target "/lib"))))))
    (synopsis (package-synopsis gcc))
    (description (package-description gcc))
    (home-page (package-home-page gcc))
    (license license:gpl3+)))

(define-public wii-newlib
  (package
    (name "wii-newlib")
    (version wii-newlib-version)
    (source wii-newlib-source)
    (build-system gnu-build-system)
    (arguments
     `(#:out-of-source? #t
       #:configure-flags
       (list (string-append "--target=" ,wii-target)
             "CFLAGS_FOR_TARGET=-O2 -ffunction-sections -fdata-sections"
             "--enable-newlib-mb"
             "--disable-nls")
       #:phases
       (modify-phases %standard-phases
         (add-after 'unpack 'fix-references-to-/bin/sh
           (lambda _
             (substitute* '("libgloss/rs6000/Makefile.in"
                            "libgloss/libnosys/Makefile.in"
                            "libgloss/libsysbase/Makefile.in"
                            "libgloss/Makefile.in")
               (("/bin/sh") (which "sh")))
             #t)))))
    (native-inputs
     `(("wii-binutils" ,wii-binutils)
       ("wii-bootstrap-gcc" ,wii-bootstrap-gcc)
       ("texinfo" ,texinfo)))
    (home-page "http://www.sourceware.org/newlib/")
    (synopsis "C library for use on embedded systems")
    (description "Newlib is a C library intended for use on embedded
systems.  It is a conglomeration of several library parts that are easily
usable on embedded products.")
    (license (license:non-copyleft
              "https://www.sourceware.org/newlib/COPYING.NEWLIB"))))

(define-public wii-gcc
  (package
    (inherit wii-bootstrap-gcc)
    (name "wii-gcc")
    (native-inputs
     `(("wii-newlib" ,wii-newlib)
       ("devkit-buildscripts" ,devkit-buildscripts-source)
       ("devkitppc-rules" ,devkitppc-rules-source)
       ,@(package-native-inputs wii-bootstrap-gcc)))
    (arguments
     `(#:modules ((guix build gnu-build-system)
                  (guix build utils)
                  (srfi srfi-1)
                  (srfi srfi-26)
                  (ice-9 regex))
       ,@(substitute-keyword-arguments
             (package-arguments wii-bootstrap-gcc)
           ((#:configure-flags flags)
            `(append
              (list 
               "CFLAGS_FOR_TARGET=-O2 -ffunction-sections -fdata-sections"
               "CXXFLAGS_FOR_TARGET=-O2 -ffunction-sections -fdata-sections"
               "LDFLAGS_FOR_TARGET="
               "--enable-languages=c,c++,lto"
               "--enable-libstdcxx-time=yes"
               "--enable-libstdcxx-filesystem-ts"
               "--enable-threads=dkp"
               "--enable-lto"
               "--enable-cxx-flags=-ffunction-sections -fdata-sections"
               (string-append "--with-headers="
                              (assoc-ref %build-inputs "wii-newlib")
                              "/" ,wii-target "/include")
               "--with-cpu=750")
              (remove (cut string-match
                           "--(without-headers|enable-languages.*)" <>)
                      ,flags)))
           ((#:phases phases)
            `(modify-phases ,phases
               (replace 'build
                 (lambda _
                   (invoke "make" "-j" (number->string (parallel-job-count)))))
               (replace 'install
                 (lambda _
                   (invoke "make" "-j" (number->string (parallel-job-count))
                           "install-strip")))
               (add-after 'install 'install-ld-scripts
                 (lambda* (#:key inputs outputs #:allow-other-keys)
                   (for-each
                    (lambda (file)
                      (install-file file
                                    (string-append
                                     (assoc-ref outputs "out")
                                     "/" ,wii-target "/lib")))
                    (find-files (string-append
                                 (assoc-ref inputs "devkit-buildscripts")
                                 "/dkppc/crtls")))
                   #t))
               (add-after 'install 'install-rulesets
                 (lambda* (#:key inputs outputs #:allow-other-keys)
                   (let* ((out (assoc-ref outputs "out"))
                          (old-rules-dir (assoc-ref inputs "devkitppc-rules")))
                     (with-directory-excursion old-rules-dir
                       (for-each
                        (lambda (file)
                          (install-file file out))
                        (find-files ".")))
                     #t))))))))))

(define libstdc++-powerpc-eabi
  (let ((libstdc++ (make-libstdc++ wii-gcc)))
    (package (inherit libstdc++)
      (name "libstdc++-powerpc-eabi")
      (arguments
       (substitute-keyword-arguments (package-arguments libstdc++)
         ((#:configure-flags flags)
          ``("--target=powerpc-eabi"
             "--host=powerpc-eabi"
             "--disable-libstdcxx-pch"
             "--disable-multilib"
             "--disable-shared"
             "--disable-tls"
             "--disable-plugin"
             "--with-newlib"
             "--with-cpu=750"
             ,(string-append "--with-gxx-include-dir="
                             (assoc-ref %outputs "out")
                             "/powerpc-eabi/include")))))
      (native-inputs
       `(("wii-newlib" ,wii-newlib)
         ("wii-gcc" ,wii-gcc)
         ,@(package-native-inputs libstdc++))))))

(define-public devkitppc-toolchain
  (let ((newlib-with-wii-gcc
         (package (inherit wii-newlib)
                  (native-inputs
                   (alist-replace "wii-bootstrap-gcc" (list wii-gcc)
                                  (package-native-inputs wii-newlib))))))
    (package
      (name "devkitppc-toolchain")
      (version (package-version wii-gcc))
      (source #f)
      (build-system trivial-build-system)
      (arguments
       '(#:modules ((guix build union))
         #:builder
         (begin
           (use-modules (ice-9 match)
                        (guix build union))
           (match %build-inputs
             (((names . directories) ...)
              (union-build (assoc-ref %outputs "out")
                           directories)
              #t)))))
      (propagated-inputs
       `(("wii-binutils" ,wii-binutils)
         ("wii-libstdc++" ,libstdc++-powerpc-eabi)
         ("wii-gcc" ,wii-gcc)
         ("wii-newlib" ,wii-newlib)))
      (native-search-paths
       (list (search-path-specification
              (variable "DEVKITPRO")
              (files '("")))
             (search-path-specification
              (variable "DEVKITPPC")
              (files '("")))))
      (synopsis "Complete GCC tool chain for Wii homebrew development")
      (description "This package provides a complete GCC tool chain for Wii
homebrew development.  This includes the GCC powerpc-eabi cross compiler and
newlib as the C library.  The supported programming languages are C and C++.")
      (home-page "https://devkitpro.org")
      (license (package-license wii-gcc)))))

(define-public gamecube-tools
  (package
    (name "gamecube-tools")
    (version "1.0.2")
    (source (origin
              (method git-fetch)
              (uri (git-reference
                    (url "https://github.com/devkitPro/gamecube-tools")
                    (commit (string-append "v" version))))
              (sha256
               (base32
                "0zvpkzqvl8iv4ndzhkjkmrzpampyzgb91spv0h2x2arl8zy4z7ca"))))
    (build-system gnu-build-system)
    (arguments
     '(#:tests? #f)) ; no check target
    (native-inputs
     `(("autoconf" ,autoconf)
       ("automake" ,automake)
       ("libtool" ,libtool)
       ("which" ,which)))
    (inputs
     `(("freeimage" ,freeimage)
       ("mesa" ,mesa)))
    (home-page (package-home-page devkitppc-toolchain))
    (synopsis "C Library for Wii and Gamecube homebrew")
    (description "libogc is a collection of low-level libraries for the GameCube
and Wii.  It is designed to be used with the devkitPPC toolchain.")
    (license license:gpl2+)))

(define-public libogc
  (package
    (name "libogc")
    (version "1.8.22")
    (source (origin
              (method git-fetch)
              (uri (git-reference
                    (url "https://github.com/devkitPro/libogc")
                    (commit (string-append "v" version))))
              (sha256
               (base32
                "1ckn6g2nihsqmz8v3avvf5l4m3dl1417zv3zmx0c1zkfvh6ay9yh"))))
    (build-system gnu-build-system)
    (arguments
     '(#:tests? #f ; no check target
       #:phases
       (modify-phases %standard-phases
         (replace 'configure
           (lambda* (#:key inputs outputs #:allow-other-keys)
             (let ((out (assoc-ref outputs "out"))
                   (devkitppc (assoc-ref inputs "devkitppc")))
               (setenv "DEVKITPRO" devkitppc)
               (setenv "DEVKITPPC" devkitppc)
               (substitute* "Makefile"
                 ;; Use date and time of upstream's release commit.
                 (("__DATE__") "20190326")
                 (("__TIME__") "010902")
                 (("\\$\\(DESTDIR\\)\\$\\(DEVKITPRO\\)/libogc")
                  (string-append out "/libogc")))
               #t)))
         (delete 'build))))
    (inputs
     `(("devkitppc" ,devkitppc-toolchain)))
    (home-page (package-home-page devkitppc-toolchain))
    (synopsis "C Library for Wii and Gamecube homebrew")
    (description "libogc is a collection of low-level libraries for the GameCube
and Wii.  It is designed to be used with the devkitPPC toolchain.")
    (license license:bsd-3)))

(define-public libfat
  (package
    (name "libfat")
    (version "1.1.3")
    (source (origin
              (method git-fetch)
              (uri (git-reference
                    (url "https://github.com/devkitPro/libfat")
                    (commit (string-append "v" version))))
              (sha256
               (base32
                "1rxf4ghnlwcg5b9n0djwsfpjnvg4a6kmis28yj12vlsjpggh44ay"))))
    (build-system gnu-build-system)
    (arguments
     '(#:tests? #f ; no check target
       #:phases
       (modify-phases %standard-phases
         (replace 'configure
           (lambda* (#:key inputs outputs #:allow-other-keys)
             (let ((out (assoc-ref outputs "out"))
                   (devkitppc (assoc-ref inputs "devkitppc"))
                   (libogc (assoc-ref inputs "libogc")))
               (setenv "DEVKITPRO" devkitppc)
               (setenv "DEVKITPPC" devkitppc)
               (substitute* "libogc/Makefile"
                 (("\\$\\(DESTDIR\\)\\$\\(DEVKITPRO\\)/libogc")
                  (string-append out "/libogc"))
                 (("\\$\\(LIBOGC_INC)")
                  (string-append libogc "/libogc/include"))
                 (("\\$\\(LIBOGC_LIB)")
                  (string-append libogc "/libogc/lib")))
               #t)))
         (replace 'build
           (lambda _
             (invoke "make" "-j" (number->string (parallel-job-count))
                     "wii-release")))
         (replace 'install
           (lambda _
             (invoke "make" "-j" (number->string (parallel-job-count))
                     "ogc-install"))))))
    (inputs
     `(("devkitppc" ,devkitppc-toolchain)
       ("libogc" ,libogc)))
    (home-page (package-home-page devkitppc-toolchain))
    (synopsis "FAT library for GBA, DS, Gamecube and Wii")
    (description
     "libfat is a FAT library for the GBA, DS, Gamecube and Wii.")
    (license license:bsd-3)))

(define-public devkitpro-tools
  (package
    (name "devkitpro-tools")
    (version "1.0.2")
    (source (origin
              (method git-fetch)
              (uri (git-reference
                    (url "https://github.com/devkitPro/general-tools")
                    (commit (string-append "v" version))))
              (sha256
               (base32
                "1ymk1bhrprvfnnfvpfzlmmxwfvhajmiddqh5ics9y64db63n8kd2"))))
    (build-system gnu-build-system)
    (arguments
     '(#:tests? #f)) ; no check target
    (native-inputs
     `(("autoconf" ,autoconf)
       ("automake" ,automake)))
    (home-page (package-home-page devkitppc-toolchain))
    (synopsis "General utilities for devkitPro")
    (description "General utilities for devkitPro")
    (license license:gpl3+)))

(define-public devkitpro-portlibs
  (let ((commit "644a77c8074d76bad80f917373a5aad22dca1217")
        (revision "1"))
    (package
      (name "devkitpro-portlibs")
      (version (git-version "0" revision commit))
      (source (origin
                (method git-fetch)
                (uri (git-reference
                      (url "https://github.com/devkitPro/portlibs")
                      (commit commit)))
                (sha256
                 (base32
                  "1p5d7ay5dmxr173idah0bj27hl1b0nqy8gr703lvdvvj598rpzr1"))))
      (build-system gnu-build-system)
      (arguments
       `(#:tests? #f ; no check target
         #:phases
         (modify-phases %standard-phases
           (add-after 'unpack 'set-env-vars
             (lambda* (#:key inputs outputs #:allow-other-keys)
               (let* ((devkitppc (assoc-ref inputs "devkitppc"))
                      (out (assoc-ref outputs "out"))
                      (cflags "-O2 -mcpu=750 -meabi -mhard-float -ffunction-sections -fdata-sections"))
                 (setenv "CFLAGS" cflags)
                 (setenv "CXXFLAGS" cflags)
                 (setenv "CPPFLAGS"
                         (string-append "-DGEKKO -I" out "/include"))
                 (setenv "CHOST" "powerpc-eabi")
                 (setenv "DEVKITPPC" devkitppc)
                 (setenv "DEVKITPRO" devkitppc)
                 (setenv "LDFLAGS"
                         (string-append "-L" out "/lib"))
                 (setenv "PATH" (string-append out "/bin:"
                                               (getenv "PATH")))
                 (setenv "PORTLIBS_ROOT" out)
                 (setenv "PORTLIBS_PREFIX" out)
                 (setenv "PKG_CONFIG_LIBDIR"
                         (string-append out "/lib/pkgconfig"))
                 (setenv "CONFIG_SHELL" (which "sh"))
                 (setenv "SHELL" (which "sh"))
                 #t)))
           (add-after 'unpack 'unpack-bzip2
             (lambda* (#:key inputs #:allow-other-keys)
               (let ((bzip2 (assoc-ref inputs "bzip2")))
                 (invoke "tar" "xvf" bzip2)
                 (chdir (string-append "bzip2-" ,(package-version bzip2)))
                 #t)))
           (delete 'configure)
           (replace 'build
             (lambda _
               (invoke "make" "-j" (number->string (parallel-job-count))
                       "CC=powerpc-eabi-gcc" "AR=powerpc-eabi-ar"
                       "RANLIB=powerpc-eabi-ranlib" "libbz2.a")))
           (replace 'install
             (lambda* (#:key outputs #:allow-other-keys)
               (let* ((out (assoc-ref outputs "out"))
                      (include-dir (string-append out "/include"))
                      (lib-dir (string-append out "/lib")))
                 (install-file "bzlib.h" include-dir)
                 (install-file "libbz2.a" lib-dir)
                 #t)))
           (add-after 'install 'unpack-zlib
             (lambda* (#:key inputs #:allow-other-keys)
               (let ((zlib (assoc-ref inputs "zlib")))
                 (chdir "..")
                 (invoke "tar" "xvf" zlib)
                 (chdir (string-append "zlib-" ,(package-version zlib)))
                 #t)))
           (add-after 'unpack-zlib 'configure-zlib
             (lambda* (#:key outputs #:allow-other-keys)
               (let ((out (assoc-ref outputs "out")))
                 (invoke "sh" "configure" (string-append "--prefix=" out)
                         "--static"))))
           (add-after 'configure-zlib 'build-zlib
             (lambda _
               (invoke "make" "-j" (number->string (parallel-job-count))
                       "libz.a" (string-append "SHELL=" (which "sh")))))
           (add-after 'build-zlib 'install-zlib
             (lambda _
               (invoke "make" "-j" (number->string (parallel-job-count))
                       "install" (string-append "SHELL=" (which "sh")))))
           (add-after 'install-zlib 'unpack-libpng
             (lambda* (#:key inputs #:allow-other-keys)
               (let ((libpng (assoc-ref inputs "libpng")))
                 (chdir "..")
                 (invoke "tar" "xvf" libpng)
                 (chdir (string-append "libpng-" ,(package-version libpng)))
                 #t)))
           (add-after 'unpack-libpng 'configure-libpng
             (lambda* (#:key outputs #:allow-other-keys)
               (let ((out (assoc-ref outputs "out")))
                 (invoke "sh" "configure"
                         (string-append "--prefix=" out)
                         "--host=powerpc-eabi"
                         "--disable-shared" "--enable-static"))))
           (add-after 'configure-libpng 'build-libpng
             (lambda _
               (invoke "make" "-j" (number->string (parallel-job-count)))))
           (add-after 'build-libpng 'install-libpng
             (lambda _
               (invoke "make" "-j" (number->string (parallel-job-count))
                       "install")))
           (add-after 'install-libpng 'unpack-freetype
             (lambda* (#:key inputs #:allow-other-keys)
               (let ((freetype (assoc-ref inputs "freetype")))
                 (chdir "..")
                 (invoke "tar" "xvf" freetype)
                 (chdir (string-append "freetype-" ,(package-version freetype)))
                 #t)))
           (add-after 'unpack-freetype 'configure-freetype
             (lambda* (#:key outputs #:allow-other-keys)
               (let ((out (assoc-ref outputs "out")))
                 (substitute* "builds/unix/configure"
                   (("/bin/sh") (which "sh")))
                 (invoke "sh" "configure"
                         (string-append "--prefix=" out)
                         "--host=powerpc-eabi"
                         "--disable-shared" "--enable-static"
                         "--with-zlib" "--with-bzip2" "--with-png"))))
           (add-after 'configure-freetype 'build-freetype
             (lambda _
               (invoke "make" "-j" (number->string (parallel-job-count)))))
           (add-after 'build-freetype 'install-freetype
             (lambda _
               (invoke "make" "-j" (number->string (parallel-job-count))
                       "install")))
           (add-after 'install-freetype 'unpack-mxml
             (lambda* (#:key inputs #:allow-other-keys)
               (chdir "..")
               (copy-recursively (assoc-ref inputs "mxml") "mxml")
               (chdir "mxml")
               #t))
           (add-after 'unpack-mxml 'configure-mxml
             (lambda* (#:key outputs #:allow-other-keys)
               (let ((out (assoc-ref outputs "out")))
                 (invoke "sh" "configure"
                         (string-append "--prefix=" out)
                         "--host=powerpc-eabi"
                         "--disable-shared" "--enable-static"
                         "--disable-threads"))))
           (add-after 'configure-mxml 'build-mxml
             (lambda _
               (invoke "make" "-j" (number->string (parallel-job-count))
                       (string-append "SHELL=" (which "sh")))))
           (add-after 'build-mxml 'install-mxml
             (lambda _
               (invoke "make" "-j" (number->string (parallel-job-count))
                       "install" (string-append "SHELL=" (which "sh"))))))))
      (native-inputs
       `(("bzip2" ,(package-source bzip2))
         ("freetype" ,(package-source freetype))
         ("libpng" ,(package-source libpng))
         ("mxml"
          ,(origin
             (method git-fetch)
             (uri (git-reference
                   (url "https://github.com/michaelrsweet/mxml")
                   (commit (string-append "v2.12"))))
             (file-name (git-file-name "mxml" "2.12"))
             (sha256
              (base32
               "1g5a1dfw3x4ap7p9cx6frh7ss8wkmqlsw2y64y2vw4g8yhp4k8wp"))))
         ("pkg-config" ,pkg-config)
         ("zlib" ,(package-source zlib))))
      (inputs
       `(("devkitppc" ,devkitppc-toolchain)))
      (home-page (package-home-page devkitppc-toolchain))
      (synopsis "Various libraries for use on the Wii")
      (description "Various libraries for use on the Wii")
      (license (list (package-license bzip2)
                     (package-license freetype)
                     (package-license libpng)
                     (package-license zlib)
                     license:lgpl2.0)))))

(define-public wiimms-iso-tools
  (package
    (name "wiimms-iso-tools")
    (version "3.02a")
    (source
     (origin
       (method url-fetch)
       (uri (string-append "https://download.wiimm.de/source/wiimms-iso-tools"
                           "/wiimms-iso-tools.source-" version ".txz"))
       (file-name (string-append name "-" version ".tar.xz"))
       (sha256
        (base32 "0h2xvkv6s1yxzlwn09xh94sipx59iy4af9q6ih7vy364rz11madp"))))
    (build-system gnu-build-system)
    (arguments
     '(#:make-flags (list (string-append "INSTALL_PATH="
                                         (assoc-ref %outputs "out")))
       #:tests? #f ; no check target
       #:phases
       (modify-phases %standard-phases
         ;; While there's no configure script, install.sh unnecessarily attempts
         ;; to use sudo.
         (replace 'configure
           (lambda _
             (substitute* "Makefile"
               (("install\\.sh --make") "install.sh --no-sudo --make"))
             #t)))))
    (inputs
     `(("ncurses" ,ncurses)))
    (home-page "https://wit.wiimm.de/")
    (synopsis "Tools to manipulate Wii and GameCube images and containers")
    (description
     "Wiimms ISO Tools is a set of command line tools to manipulate Wii and
GameCube ISO images and WBFS containers.  The toolset consists of the following
tools:
@table @asis
@item @code{wit} (Wiimms ISO Tool)
This is the main ISO manipulation tool.  It can list, analyze, verify, convert,
split, join, patch, mix, extract, compose, rename and compare Wii and GameCube
images.  It also can create and dump different other Wii file formats.
@item @code{wwt} (Wiimms WBFS Tool)
This is the main WBFS manipulation tool.  It can create, check, repair, verify
and clone WBFS files and partitions.  It can list, add, extract, remove, rename
and recover ISO images as part of a WBFS.
@item @code{wdf} (Wiimms WDF Tool)
@code{wdf} is a support tool for WDF, WIA, CISO and GCZ images.  It converts
(packs and unpacks), compares and dumps WDF and CISO images.  Additionally it
dumps WIA and GCT image and unpacks WIA images.  The default command depends on
the program file name (see command descriptions).  Usual names are @code{wdf},
@code{unwdf}, @code{wdf-cat}, @code{wdf-cmp} and @code{wdf-dump} (with or
without minus signs).  @code{wdf +CAT} replaces the old tool @code{wdf-cat} and
@code{wdf +DUMP} the old tool @code{wdf-dump}.
@item @code{wfuse} (Wiimms FUSE Tool)
Mount a Wii or GameCube image or a WBFS file or partition to a mount point
using FUSE (Filesystem in USErspace).  Use 'wfuse --umount mountdir' for
unmounting.
@end table")
    (license license:gpl2+)))

(define-public wiiload
  (package
    (name "wiiload")
    (version "0.5.1")
    (source (origin
              (method url-fetch)
              (uri (string-append "https://github.com/devkitPro/wiiload/"
                                  "releases/download/v" version
                                  "/wiiload-" version ".tar.bz2"))
              (sha256
               (base32
                "15cmk8lcvjj5b0ahsvr270jbwry74j9jhljp76yhksk0ka0ps8c3"))))
    (build-system gnu-build-system)
    (inputs
     `(("zlib" ,zlib)))
    (home-page "https://github.com/devkitPro/wiiload")
    (synopsis "Wii executables over a network to the Wii")
    (description "Wiiload is a method of loading .dol and .elf files over a
network.  Also, Wiiload can be used to remotely install homebrew applications
onto an SD card.")
    (license license:gpl2+)))
